Next | Prev | Up | Top | Contents | Index

Deadline Scheduling Subroutines

The following example contains two subroutines that simplify the interface to the schedctl() function for deadline scheduling. If the code is compiled with variable UNIT_TEST defined, it compiles a main() procedure that runs a test. Otherwise it compiles only the functions. A test run of the program resembles the following:

% setDeadline 20 100
schedule pid 0 for 20% of 100ms --> 0
policy DL_ONLY-->0
policy DL_ANY-->0
policy DL_RELEASE-->0
On a uniprocessor, a request for much more than 20% of the CPU is rejected. On a multiprocessor, a request for 98% or 99% is generally successful.

Example A-8 : Helper Functions for Using schedctl()

/* 
|| Issue the schedctl(2) calls to set up deadline scheduling, using
|| the simpler interface of npri(1). That is, where schedctl() requires
|| you to set up a structure containing two intervals in nanoseconds,
|| setDeadlinePct() lets you specify an interval in milliseconds and a
|| percentage duty cycle.
||
|| As a bonus, setDeadlinePolicy() is a short way to call for any of
|| the four policies, DL_ONLY, DL_ANY, DL_RELEASE (the rest of the period)
|| and DL_BLOCK (for the rest of the period).
*/
#include <errno.h>
#include <sys/schedctl.h>
#include <stdio.h> /* for stderr, perror */
/*
|| This local function does the arithmetic to convert a count of
|| milliseconds into the fields of a timestruc_t.
*/
static void putMSinTimestruc(timestruc_t *ts, const int milliseconds)
{
    int ms = milliseconds;  
    if (1000 > ms)
        ts->tv_sec = 0;
    else
    { /* set the seconds as well as the nanoseconds */
        ts->tv_sec = ms/1000;
        ms %= 1000;
    }
    /* set the nanoseconds: 1e3*1e6 == 1e9 */
    ts->tv_nsec = ms*1000000;
}
/*
|| Request deadline scheduling for the specified PID (0 for "self"),
|| in terms of a period in milliseconds and a percentage.
*/  
int setDeadlinePct(int pid, int period, int pct)
{
    struct sched_deadline dd = {{0,0},{0,0}};
    int retval;
    putMSinTimestruc(&dd.dl_period, period);
    putMSinTimestruc(&dd.dl_alloc, (period * pct)/100);
    if (-1 == (retval = schedctl(DEADLINE, pid, &dd)) )
    {
        if (ENOSPC == errno)
        { /* system cannot guarantee that duty cycle */
            fprintf(stderr,"schedctl: cannot promise %d%% of %dms\n",
                                                     pct, period);
        }
        else perror("schedctl");
    }
    return retval;
}
/*
|| Request one of the constants defined in schedctl.h as a new
|| scheduling policy for the specified PID.
||
|| Note: the constants DL_ONLY, etc., are declared in schedctl.h
|| as type-casts to (struct sched_deadline *).  That is why this
|| function speficies that type for its second argument -- when
|| it logically should be simply "int."
*/
int setDeadlinePolicy(int pid, struct sched_deadline * policy)
{
    int retval = schedctl(DEADLINE,pid,policy);
    if (-1 == retval)
    {
        char msg[64];
        sprintf(msg,"schedctl(DEADLINE,%d,%ld)",pid,policy);
        perror(msg);
    }
    return retval;
}
#ifdef UNIT_TEST
int main(int argc, char **argv)
{
    int pct = 25;
    int per = 100;
    int pid = 0; /* which means "self" to schedctl() */
    if (1 < argc)
    {
        pct = atoi(argv[1]);
    }
    if (2 < argc)
    {
        per = atoi(argv[2]);
    }
    if (3 < argc)
    {
        pid = atoi(argv[3]);
    }
    if ( (4 < argc) || (0==pct) || (0==per) )
    {
        fprintf(stderr,
    "usage: setDeadline [ pct_duty_cycle [ period_ms [ pid ] ] ]\n");
        exit();
    }
    printf("schedule pid %d for %d%% of %dms --> %d\n",
                        pid, pct, per, setDeadlinePct( pid, per, pct));
    printf("policy DL_ONLY-->%d\n", setDeadlinePolicy(pid,DL_ONLY));        
    printf("policy DL_ANY-->%d\n", setDeadlinePolicy(pid,DL_ANY));      
    printf("policy DL_RELEASE-->%d\n", setDeadlinePolicy(pid,DL_RELEASE));  
}
#endif 


Next | Prev | Up | Top | Contents | Index